/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package packetTracker;

import beans.Mapa;
import beans.Pedido;
import beans.Vehiculo;
import colonia.ColoniaHormigas;
import config.GestorVehiculos;
import config.Parameters;
import config.Reloj;
import facade.PedidosFacade;
import facade.VehiculoFacade;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import javax.servlet.ServletContext;

/**
 *
 * @author Shadow
 */
public class PacketTracker implements Runnable {

    public static PacketTracker _packetTracker;
    private static VehiculoFacade vehiculoFacade = new VehiculoFacade();
    private static PedidosFacade pedidosFacade = new PedidosFacade();
    public static final int ventana = 4;
    public static Mapa mapa;
    public static ArrayList<Pedido> pedidos = new ArrayList<>();
    public static String prefijo="dat";
    private boolean _stopped = false;
    private ServletContext servletContext;
    private boolean running=false;
    private Thread simulacion;
    private int turnoActual = 1;
    private int incidenciaPorTurno = 0;
    private static boolean terminar = false;

    public boolean isTerminar() {
        return terminar;
    }

    public void setTerminar(boolean terminar) {
        PacketTracker.terminar = terminar;
    }
    
    public synchronized static PacketTracker getInstancia(){
        if (_packetTracker == null)
            _packetTracker = new PacketTracker();
        return _packetTracker;
    }
     
    
    public synchronized void runSimulation(){
        if (running) return;
        running=true;
        simulacion = new Thread(this);
        simulacion.start();
        
    }
    
    public void detenerSimulacion(){
        this._stopped = true;
    }
    
    public void terminarHilo(){
        this.terminar=true;
    }
    
    public void seguirSimulacion(){
        this._stopped = false;
    }
    
    @Override
    public void run() {
        //iniciar tiempo a 00:00
        Reloj reloj = Reloj.getInstancia();
        GestorVehiculos gestorVehiculos = GestorVehiculos.getInstancia();
        gestorVehiculos.crearVehiculos();
        ColoniaHormigas.crearNodosMapa(); 
        ColoniaHormigas.initFeronoma();
        Calendar proxDia = (Calendar)reloj.getFecha().clone();
        proxDia.add(Calendar.DAY_OF_MONTH, 1);
        pedidos = Dispatcher.siguientesPedidos(reloj.getHora(),reloj.getMinuto());
        Calendar proxVentana = (Calendar)reloj.getFecha().clone();
        proxVentana.add(Calendar.MINUTE, ventana);
        boolean hayDia = false; 
        ArrayList<Pedido> pedidosNuevos;
        reloj.iniciar();
        Calendar fechaAux;
        ArrayList<Pedido> pedidosVencidos = new ArrayList<>();
        gestorVehiculos.actualizaTurno();
        while (true) {
            if(PacketTracker.terminar){
                //System.out.println("salio del algoritmoooooooo");
                break;
            }
            if (_stopped) continue;
            if(proxVentana.after(fechaAux = (Calendar)reloj.getFecha().clone()))continue;
            fechaAux = (Calendar)proxVentana.clone();
            proxVentana.add(Calendar.MINUTE, ventana);
            reloj.pausar();
            Date b = new Date();
            reloj.setFecha((Calendar) fechaAux.clone());
//            for(int o=0; o < pedidos.size();o++){
//                if (pedidosVencidos.contains(pedidos.get(o))) continue;
//                    if (pedidos.get(o).getFechaVencimiento().before(reloj.getFecha())) {
////                        pedidosVencidos.add(pedidos.get(o));
//                        System.out.println("Tarde " + reloj.getFechaString("dd/MM/yyy HH:mm")+" Pedido: " + pedidos.get(o).getIdPedido() + " vence: " + pedidos.get(o).getFechaString(pedidos.get(o).getFechaVencimiento(), "dd/MM/yyy HH:mm")+" X = "+pedidos.get(o).getDestino().getX()+", Y = "+pedidos.get(o).getDestino().getY());
//                        break;
//                    }
//            }
            ColoniaHormigas.obtenerSolucionInversa(pedidos);
            Date a = new Date();
            gestorVehiculos.asignarRutas(ColoniaHormigas.mejoresHormigas,ColoniaHormigas.pedidosAsignados);
            gestorVehiculos.actualizarVehiculosYOrdenes(ventana, pedidos);
            if(proxDia.compareTo(reloj.getFecha())<=0){
                proxDia = (Calendar)reloj.getFecha().clone();
                proxDia.add(Calendar.DAY_OF_MONTH, 1);
                Parameters._diasSimulados++;
                String dia = reloj.getFechaString("dd");
                String mes = reloj.getFechaString("MM");
                String anho = reloj.getFechaString("yyyy");
                hayDia = Dispatcher.leerEventosDia(dia,mes,anho);
                if(!hayDia && pedidos.isEmpty()){ 
                    reloj.detener();
                    break;
                }
                if(PacketTracker.terminar){
                   // System.out.println("salio del algoritmoooooooo");
                    continue;
                }
            }
            pedidosNuevos = Dispatcher.siguientesPedidos(reloj.getHora(),reloj.getMinuto());
            pedidos.addAll(pedidosNuevos);
            if (reloj.esTiempoIncidencia()){
                simularIncidencia();
            }
            gestorVehiculos.actualizaTurno();
            if (turnoActual != reloj.getTurnoActual()){
                GestorVehiculos.getInstancia().restauraVehiculos();
                turnoActual = reloj.getTurnoActual();
                incidenciaPorTurno = 0;
            }
            
            calcularTiempoLlegadaPedidos();
            reloj.continuar();
        }
        reloj.detener();
        String mensaje = "";
        try{
            vehiculoFacade.ingresarIncidencias();
            vehiculoFacade.ingresarHorasExtras();
            mensaje = pedidosFacade.actualizarPedidos();
        }catch(SQLException | InstantiationException | IllegalAccessException | ClassNotFoundException e){
            
        }
       // System.out.println("termino la simulacion" + "     -    "+mensaje);
    }
    private void calcularTiempoLlegadaPedidos(){
        for (Pedido pedido:pedidos){
            Vehiculo v = estaAsignado(pedido);
            if (v != null){
                v.calcularLlegada(pedido);
            }else{
                pedido.setTiempoEstimadoLlegada(-1);
            }
        }
    }
    private Vehiculo estaAsignado(Pedido p){
        for (Vehiculo vehiculo:GestorVehiculos.getInstancia().getVehiculos()){
            if (vehiculo.getListaPedido().contains(p))
                return vehiculo;
        }
        return null;
    }
    private void simularIncidencia(){
        if (incidenciaPorTurno >= Parameters.MAX_INCIDENCIAS_TURNO) return;
        Pedido pedidoAux = null;
        for(Vehiculo vehiculo:GestorVehiculos.getInstancia().getVehiculos()){
            if (vehiculo.tienePedidoPrioridad(2)){
                vehiculo.desactivar();
                break;
            }
        }
        incidenciaPorTurno++;
    }
    public static void main(String[] args){
        PacketTracker pT = PacketTracker.getInstancia();
        pT.runSimulation();
    }

    /**
     * @return the servletContext
     */
    public ServletContext getServletContext() {
        return servletContext;
    }

    /**
     * @param servletContext the servletContext to set
     */
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    public boolean isRunning() {
        return running;
    }
}
